package compoundDB.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import compoundDB.core.GUIController;
import compoundDB.database.enumeration.DataType;

/**
 *
 * @author User
 */
@SuppressWarnings("serial")
public class DialogCol extends JDialog
{

    private static final int dialogWidth = 300;
    private static final int dialogHieght = 200;
    private static final String hireString = "Add";
    private static final String fireString = "Delete";
    private static final String editString = "Edit";
    private static final String[] dataTypes = new String[]{"String", "Long", "Integer", "Float", "Double"/*, "Bytes"*/};
    public static final int gapBetweenButs = 5;
    private JList list;
    private DefaultListModel listModel;
    private JButton fireButton;
    private JButton editButton;
    private JTextField employeeName;
    private GUIController guic;
    private ColumnHolderListener observer;
    private Icon icon = new Icon()
    {

        @Override
        public int getIconHeight()
        {
            return 0;
        }

        @Override
        public int getIconWidth()
        {
            return 0;
        }

        @Override
        public void paintIcon(Component c, Graphics g, int x, int y)
        {
        }
    };
    private DialogCol thisDialog;

    /**
     * Creates a column editor dialog box from the information given
     * @param columns the names of the existing columns
     * @param guic the guic that holds the actual columns (so they can be changed automatically)
     * @param observer the observer who is listening for the change
     */
    public DialogCol(String[] columns, GUIController guic, ColumnHolderListener observer)
    {
        this.observer = observer;
        this.guic = guic;
        thisDialog = this;
        setUpDialog();
        JPanel cont = new JPanel();
        cont.setLayout(new BorderLayout());
        cont.add(setUpList(columns), BorderLayout.CENTER);
        cont.add(setUpButtons(), BorderLayout.PAGE_END);
        setContentPane(cont);
        setVisible(true);
    }

    /**
     * Sets Up the buttons and the text box for at the bottem of the dialog
     * @return the component containing all the smaller component
     */
    private Component setUpButtons()
    {
        JButton hireButton = new JButton(hireString);
        HireListener hireListener = new HireListener(hireButton);
        hireButton.setActionCommand(hireString);
        hireButton.addActionListener(hireListener);
        hireButton.setEnabled(false);

        fireButton = new JButton(fireString);
        fireButton.setActionCommand(fireString);
        fireButton.addActionListener(new FireListener());

        editButton = new JButton(editString);
        editButton.setActionCommand(editString);
        editButton.addActionListener(new EditListener());

        employeeName = new JTextFieldFileName(30, true, false, true);
        employeeName.addActionListener(hireListener);
        employeeName.getDocument().addDocumentListener(hireListener);

        // Create a panel that uses BoxLayout.
        JPanel butPan = new JPanel();
        butPan.setLayout(new BoxLayout(butPan, BoxLayout.LINE_AXIS));
        butPan.add(fireButton);
        butPan.add(Box.createHorizontalStrut(gapBetweenButs));
        butPan.add(new JSeparator(SwingConstants.VERTICAL));
        butPan.add(Box.createHorizontalStrut(gapBetweenButs));
        butPan.add(employeeName);
        butPan.add(hireButton);
        butPan.add(Box.createHorizontalStrut(gapBetweenButs));
        butPan.add(new JSeparator(SwingConstants.VERTICAL));
        butPan.add(Box.createHorizontalStrut(gapBetweenButs));
        butPan.add(editButton);
        butPan.setBorder(BorderFactory.createEmptyBorder(gapBetweenButs, gapBetweenButs, gapBetweenButs, gapBetweenButs));
        return butPan;
    }

    /**
     * Called when something has changed the columns
     */
    private void columnsChanged()
    {
        observer.updateColumns();
    }

    /**
     * Sets up the basic dialog properties
     */
    private void setUpDialog()
    {
        this.setModal(true);
        setSize(dialogWidth, dialogHieght);
        setTitle("Editing Columns");
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        Dimension size = getToolkit().getScreenSize();
        setLocation(size.width / 3 * 2 - getWidth() / 2, size.height / 3 - getHeight() / 2);

        this.setAlwaysOnTop(true);

    }

    /**
     * Sets up the list of existing column names
     * @param columns the existing column names
     * @return the components that holds all the components
     */
    private Component setUpList(String[] columns)
    {
        listModel = new DefaultListModel();
        for (int i = 0; i < columns.length; i++) {
            listModel.addElement(columns[i]);
        }

        list = new JList(listModel);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);
        list.addListSelectionListener(new ListSelectionListener()
        {

            @Override
            public void valueChanged(ListSelectionEvent e)
            {
                if (e.getValueIsAdjusting() == false) {
                    if (list.getSelectedIndex() == -1) {
                        // No selection, disable fire button.
                        fireButton.setEnabled(false);

                    } else {
                        // Selection, enable the fire button.
                        fireButton.setEnabled(true);
                    }
                }
            }
        });

        list.setVisibleRowCount(5);
        JScrollPane listScrollPane = new JScrollPane(list);

        return listScrollPane;
    }

    /**
     * Takes the spaces out of a string
     * Used because a column name cant have spaces
     * @param result string with spaces
     * @return string without spaces
     */
    private static String stripSpaces(String result)
    {
        String[] result2 = result.split(" ");
        StringBuilder rebuild = new StringBuilder();
        for (int i = 0; i < result2.length; i++) {
            rebuild.append(result2[i]);
        }
        result = rebuild.toString();
        return result;
    }

    /**
     * listener that is used to listen for when a column is deleted
     */
    class FireListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            // This method can be called only if
            // there's a valid selection
            // so go ahead and remove whatever's selected.
            int index = list.getSelectedIndex();
            guic.deleteColumn(listModel.get(index).toString());
            listModel.remove(index);
            columnsChanged();
            int size = listModel.getSize();

            if (size == 0) { // Nobody's left, disable firing.
                fireButton.setEnabled(false);

            } else { // Select an index.
                if (index == listModel.getSize()) {
                    // removed item in last position
                    index--;
                }

                list.setSelectedIndex(index);
                list.ensureIndexIsVisible(index);
            }
        }
    }

    /**
     * listener that is used to listen for when a column is edited
     */
    class EditListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            // This method can be called only if
            // there's a valid selection
            // so go ahead and remove whatever's selected.
            int index = list.getSelectedIndex();

            String orig = listModel.get(index).toString();
            String result = (String) JOptionPane.showInputDialog(thisDialog, "Choose the type of field in this column", "Choose Column type",
                    JOptionPane.PLAIN_MESSAGE, icon, null, orig);
            if (result == null) {
                // Dialog was closed Prematurely
                return;
            }
            result = stripSpaces(result);
            guic.renameColumn(orig, result);
            listModel.set(index, result);
            columnsChanged();
        }
    }

    /**
     * listener that is used to listen for when a column is added
     * This listener is shared by the text field and the hire button.
     */
    class HireListener implements ActionListener, DocumentListener
    {

        private boolean alreadyEnabled = false;
        private JButton button;

        public HireListener(JButton button)
        {
            this.button = button;
        }

        // Required by ActionListener.
        @Override
        public void actionPerformed(ActionEvent e)
        {
            String name = employeeName.getText();

            // User didn't type in a unique name...
            if (name.equals("") || alreadyInList(name)) {
                Toolkit.getDefaultToolkit().beep();
                employeeName.requestFocusInWindow();
                employeeName.selectAll();
                return;
            }
            String newCol = employeeName.getText();

            String result = (String) JOptionPane.showInputDialog(thisDialog, "Choose the type of field in this column", "Choose Column type",
                    JOptionPane.PLAIN_MESSAGE, icon, dataTypes, "String");

            if (result == null) {
                // Dialog was closed Prematurely
                return;
            }
            result = stripSpaces(result);
            int index = list.getSelectedIndex(); // get selected index
            if (index == -1) { // no selection, so insert at beginning
                index = 0;
            } else { // add after the selected item
                index++;
            }

            guic.addColumn(name, DataType.valueOf(result.toUpperCase()));
            listModel.insertElementAt(newCol, index);
            columnsChanged();
            // If we just wanted to add to the end, we'd do this:
            // listModel.addElement(employeeName.getText());

            // Reset the text field.
            employeeName.requestFocusInWindow();
            employeeName.setText("");

            // Select the new item and make it visible.
            list.setSelectedIndex(index);
            list.ensureIndexIsVisible(index);
        }

        // This method tests for string equality. You could certainly
        // get more sophisticated about the algorithm. For example,
        // you might want to ignore white space and capitalization.
        protected boolean alreadyInList(String name)
        {
            return listModel.contains(name);
        }

        // Required by DocumentListener.
        @Override
        public void insertUpdate(DocumentEvent e)
        {
            enableButton();
        }

        // Required by DocumentListener.
        @Override
        public void removeUpdate(DocumentEvent e)
        {
            handleEmptyTextField(e);
        }

        // Required by DocumentListener.
        @Override
        public void changedUpdate(DocumentEvent e)
        {
            if (!handleEmptyTextField(e)) {
                enableButton();
            }
        }

        private void enableButton()
        {
            if (!alreadyEnabled) {
                button.setEnabled(true);
            }
        }

        private boolean handleEmptyTextField(DocumentEvent e)
        {
            if (e.getDocument().getLength() <= 0) {
                button.setEnabled(false);
                alreadyEnabled = false;
                return true;
            }
            return false;
        }
    }
}
